<?php

/**
 * Class for handle all information aboult price caculation.
 *
 * @access 	public
 * @author 	Rob
 * @copyright	ResMania 2009 all rights reserved.
 * @version	1.0
 * @link		http://developer.resmania.com/api
 * @since  	11-2010
 */
class RM_HospitalityPrices_Calculator {

    /**
     * @var RM_HospitalityPrices
     */
    protected $_unitHospitalityPricesModel;
    /**
     * @var RM_HospitalityPricesConfig
     */
    protected $_unitHospitalityPricesConfigModel;
    /**
     * @var Zend_Translate
     */
    protected $_translate;
    /**
     * @var Board Type
     */
//    protected $_boardType;

    /**
     * Constructor
     *
     * @param RM_UnitDailyPrices $unitPricesModel
     * @param RM_UnitDailyPricesConfig $unitPricesConfigModel
     * @param Zend_Translate $translate
     */
    public function __construct($unitPricesModel, $unitPricesConfigModel, $translate) {
        $this->_unitHospitalityPricesModel = $unitPricesModel;
        $this->_unitHospitalityPricesConfigModel = $unitPricesConfigModel;
        $this->_translate = $translate;
    }

    /**
     * Calculate total price for one unit
     *
     * @todo add a parameter boardType to this method
     * @param RM_Prices_Information $information
     * @param bool $byStep - if true, the result will be in array (0 => array('step' => RM_Date, 'price' => float))
     */
    public function getTotalUnitPrice($information, $byStep = false) {
        $days = $information->getPeriod()->getDays();

        $total = 0;
        $totalDays = array();

        $daysNumber = count($days);

        $unit = $information->getUnit();

        $otherInfo = $information->getOtherInfo();
        if (empty($otherInfo)){
             $otherInfo['value'] = false;
        } else {
            foreach ($otherInfo as $key=>$value){
                $otherInfo['value'] = $value;
            }
        }

        foreach ($days as $day) {
            $price = $this->getDayPrice(
                            $day,
                            $daysNumber,
                            $unit,
                            $information->getPersons(),
                            $information->getPeriod()->getStart(),
                            $otherInfo['value']
            );

            if ($byStep) {
                $totalDays[] = array('step' => clone $day, 'price' => RM_Environment::getInstance()->roundPrice($price));
            } else {
                $total += $price;
            }
        }

        if ($byStep) {
            return $totalDays;
        } else {
            return RM_Environment::getInstance()->roundPrice($total);
        }
    }

    /**
     * Return price for one day. Based on weekday rate or weekend rate or week price (substracting by 7)
     *
     * @todo this method should be private or protected and board_type should be added here
     * @param RM_Date $day
     * @param int $daysNumber Total number of days for reservation
     * @param Zend_Db_Table_Row_Abstract $unit Unit that belong to reservation
     * @param int $persons Number of persons that will live in unit
     * @param date $startdatetime   the startdate of the reservation (date object)
     * @return float
     */
    public function getDayPrice($day, $daysNumber, $unit, $persons, $startdatetime = null, $otherInfo = null) {

        // get saved board type
        $module = new RM_Module_HospitalityPrices();

        $model = $this->_unitHospitalityPricesModel;
        $priceRow = $model->getByDay($unit, $day, $otherInfo);
        if ($priceRow == null) {
            return 0;
        }

        // min stay == max stay
        if ((int)$priceRow->min_stay !==0 && (int)$priceRow->max_stay !==0 && ((int)$priceRow->min_stay === (int)$priceRow->max_stay)){
            if ($daysNumber > (int)$priceRow->max_stay || $daysNumber < (int)$priceRow->min_stay){
                $msg = str_replace("[XX]", $priceRow->max_stay, $this->_translate->_('RM.Module.DailyPrices', 'DaysRetrictedTo'));
                throw new RM_Exception($msg);
            }
        }

        // min stay check
        if ($daysNumber < (int)$priceRow->min_stay) {
            $msg = str_replace("[XX]", $priceRow->min_stay, $this->_translate->_('RM.Module.HospitalityPrices', 'DaysNumberIsSmallerThanMin'));
            throw new RM_Exception($msg);
        }

        // max stay check
        if ((int)$priceRow->max_stay !== 0 && ((int)$priceRow->max_stay >= (int)$priceRow->min_stay && $daysNumber > (int)$priceRow->max_stay)) {
            $msg = str_replace("[XX]", $priceRow->max_stay, $this->_translate->_('RM.Module.HospitalityPrices', 'DaysNumberIsGreaterThanMax'));
            throw new RM_Exception($msg);
        }

        // handle if an object or string is passed for the date.
        if (is_object($startdatetime)) {
            $selectedStartDay = date("w", $startdatetime->toString("U"));
        } else {
            $selectedStartDay = date("w", strtotime($startdatetime));
        }
        // $priceRow->week_startday = -1 means that weekday restriction is disabled
        if ($priceRow->week_startday != -1) {
            if ($priceRow->week_startday != $selectedStartDay) {
                $translate = RM_Environment::getInstance()->getTranslation(RM_Environment::TRANSLATE_MAIN);
                $dayJson = $translate->_('Common.JSON', 'WeekDaysLongNumbered');
                $dayJson = str_replace(chr(39), chr(34), $dayJson); //Zend_Json::decode does not support single quotes so replace these with doubles
                $daysArray = Zend_Json::decode($dayJson);
                $msg = str_replace("[DAY]", $daysArray[$priceRow->week_startday][1], $this->_translate->_('RM.Module.HospitalityPrices', 'StartDayNotAllowed'));
                throw new RM_Exception($msg);
            }
        }

        // get price config items
        $priceConfigModel = $this->_unitHospitalityPricesConfigModel;
        $weekendPriceEnabled = $priceConfigModel->fetchValueByUnit($unit->id, 'weekend_price_enabled');
        $weekendDays = $priceConfigModel->fetchValueByUnit($unit->id, 'weekend_days');
        $price_by = $priceConfigModel->fetchValueByUnit($unit->id, 'price_by'); // price by unit or per-person

        //weekly rate
        $adultDayRate  = $priceRow->adult_weekly_price / 7;
        $childDayRate  = $priceRow->child_weekly_price / 7;
        $infantDayRate = $priceRow->infant_weekly_price / 7;

        //weekday rate
        $adultWeekdayRate  = $priceRow->adult_weekday_price;
        $childWeekdayRate  = $priceRow->child_weekday_price;
        $infantWeekdayRate = $priceRow->infant_weekday_price;

        // weekend rate
        $adultWeekendRate  = $priceRow->adult_weekend_price;
        $childWeekendRate  = $priceRow->child_weekend_price;
        $infantWeekendRate = $priceRow->infant_weekend_price;
        
        $adults = $persons->getAdults();
        $children = $persons->getChildren();
        $infants = $persons->getInfants();
        
        // return price by unit
        if ($price_by == "unit"){

            // weekly price
            if ($daysNumber >= 7) {
                $returnVal = $adultDayRate;
                if ($children) $returnVal += $childDayRate;
                if ($infants) $returnVal += $infantDayRate;
                return $returnVal;
            }

            // weekday price
            if ($weekendPriceEnabled == false) {
                $returnVal = $adultWeekdayRate;
                if ($children) $returnVal += $childWeekdayRate;
                if ($infants) $returnVal += $infantWeekdayRate;
                return $returnVal;
            }

            // weekend prices
            $weekendDays = $priceConfigModel->fetchValueByUnit($unit->id, 'weekend_days');
            if (RM_HospitalityPrices_Weekend::isWeekend($weekendDays, $day->toString('w'))) {
                $returnVal = $adultWeekendRate;
                if ($children) $returnVal += $childWeekendRate;
                if ($infants) $returnVal += $infantWeekendRate;
                return $returnVal;
            } else {
                $returnVal = $adultWeekdayRate;
                if ($children) $returnVal += $childWeekdayRate;
                if ($infants) $returnVal += $infantWeekdayRate;
                return $returnVal;
            }
        }

        // return price by persons
        if ($price_by=="person"){
       
            // weekly price
            if ($daysNumber >= 7) {
                return ($adultDayRate * $adults) + ($childDayRate * $children) + ($infantDayRate * $infants);
            }

            // weekday price
            if ($weekendPriceEnabled == false) {
                return ($adultWeekdayRate * $adults) + ($childWeekdayRate * $children) + ($infantWeekdayRate * $infants);
            }

            // weekend prices
            $weekendDays = $priceConfigModel->fetchValueByUnit($unit->id, 'weekend_days');
            if (RM_HospitalityPrices_Weekend::isWeekend($weekendDays, $day->toString('w'))) {
                return ($adultWeekendRate * $adults) + ($childWeekendRate * $children) + ($infantWeekendRate * $infants);
            } else {
                return ($adultWeekdayRate * $adults) + ($childWeekdayRate * $children) + ($infantWeekdayRate * $infants);
            }
        }
    }

    

}